/*
 * Path.cpp
 *
 *  Created on: Feb 25, 2011
 *      Author: santiago
 */

#include <iostream>
#include <vector>
#include <assert.h>

#include "TSPPath.h"
#include "TSPCostMatrix.h"
#include "GlobalDefs.h"

TSPPath::TSPPath(): _costs(NULL), _path_cost(0.0), _path() {
	_path.clear();
}

TSPPath::TSPPath(TSPCostMatrix *costs) :
	_costs(costs), _path_cost(0.0), _path() {

}

TSPPath::TSPPath(TSPCostMatrix &costs) :
	_costs(&costs), _path_cost(0.0), _path() {

}

TSPPath::TSPPath(const TSPPath &path) :
	_costs(path._costs), _path_cost(path._path_cost), _path() {

	for (unsigned int i = 0; i < path.get_size(); i++) {
		_path.push_back(path.get_node_at(i));
	}
}

TSPPath::TSPPath(const TSPPath &path, const unsigned int start_node, const unsigned int end_node) :
	_costs(path._costs), _path_cost(0.0), _path() {

	bool start_found = false;
	int start_index = 0;

	for (unsigned int i = 0; (i < path.get_size()) && !start_found; i++) {
		if (path.get_node_at(i) == start_node) {
			add_initial_node(start_node);
			start_found = true;
			start_index = i;
		}
	}

	assert(start_found);
	bool end_found = false;

	for (unsigned int i = start_index + 1; (i < path.get_size()) && !end_found; i++) {
		unsigned int node = path.get_node_at(i);
		add_node(node);

		if (node == end_node) {
			end_found = true;
		}
	}

	assert(end_found);
}

TSPPath::~TSPPath() {
}

TSPPath& TSPPath::operator=(const TSPPath &original) {
	_costs = original.get_costs();
	_path_cost = 0.0;
	_path.clear();
	_path.reserve(original.get_size());

	if (original.get_size() > 0) {
		add_initial_node(original.get_node_at(0));

		for (unsigned int i = 1; i < original.get_size(); i++) {
			add_node(original.get_node_at(i));
		}
	}

	return *this;
}

void TSPPath::add_initial_node(unsigned int node_index) {
	assert(_path.size() == 0);
	_path.push_back(node_index);
}

void TSPPath::add_node(unsigned int node_index) {
	assert(_path.size() > 0);

	unsigned int prev_node_index = _path[_path.size() - 1];
	_path.push_back(node_index);

	_path_cost += _costs->get_cost(prev_node_index, node_index);
}

bool TSPPath::contains_node(unsigned int node_index) const {
	for (unsigned int i = 0; i < _path.size(); i++) {
			if (_path[i] == node_index) {
				return true;
			}
	}
	return false;
}

bool TSPPath::contains_pair(unsigned int i_node_index,
		unsigned int j_node_index) const {
	for (unsigned int i = 0; i < _path.size() - 1; i++) {
		if ((_path[i] == i_node_index) || (_path[i] == j_node_index)) {
			return (_path[i + 1] == i_node_index) || (_path[i + 1]
					== j_node_index);
		}
	}

	return false;
}

TSPCostMatrix* TSPPath::get_costs() const {
	return _costs;
}

double TSPPath::get_path_cost() const {
	return _path_cost;
}

bool TSPPath::check_path() const {
	// TODO: siempre retorna TRUE!!!
//	if (DEBUG) cout << "[DEBUG] <TSPPath> size: " << _path.size() << endl;
	if (_path.size() < 2) return false;

	return true;
}

unsigned int TSPPath::get_size() const {
	return _path.size();
}

unsigned int TSPPath::get_node_at(unsigned int index) const {
	return _path[index];
}

void TSPPath::show() const {
	cout << "(" << _path[0];

	for (unsigned int i = 1; i < _path.size(); i++) {
		cout << "," << _path[i];
	}

	cout << ")";
}
